1   package org.apache.lucene.util;
2   
3   import org.apache.lucene.util.ByteBlockPool.Allocator;
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  public final class RecyclingByteBlockAllocator extends ByteBlockPool.Allocator {
32    private byte[][] freeByteBlocks;
33    private final int maxBufferedBlocks;
34    private int freeBlocks = 0;
35    private final Counter bytesUsed;
36    public static final int DEFAULT_BUFFERED_BLOCKS = 64;
37  
38    
39  
40  
41  
42  
43  
44  
45  
46  
47  
48    public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks,
49        Counter bytesUsed) {
50      super(blockSize);
51      freeByteBlocks = new byte[maxBufferedBlocks][];
52      this.maxBufferedBlocks = maxBufferedBlocks;
53      this.bytesUsed = bytesUsed;
54    }
55  
56    
57  
58  
59  
60  
61  
62  
63  
64    public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks) {
65      this(blockSize, maxBufferedBlocks, Counter.newCounter(false));
66    }
67  
68    
69  
70  
71  
72  
73  
74    public RecyclingByteBlockAllocator() {
75      this(ByteBlockPool.BYTE_BLOCK_SIZE, 64, Counter.newCounter(false));
76    }
77  
78    @Override
79    public byte[] getByteBlock() {
80      if (freeBlocks == 0) {
81        bytesUsed.addAndGet(blockSize);
82        return new byte[blockSize];
83      }
84      final byte[] b = freeByteBlocks[--freeBlocks];
85      freeByteBlocks[freeBlocks] = null;
86      return b;
87    }
88  
89    @Override
90    public void recycleByteBlocks(byte[][] blocks, int start, int end) {
91      final int numBlocks = Math.min(maxBufferedBlocks - freeBlocks, end - start);
92      final int size = freeBlocks + numBlocks;
93      if (size >= freeByteBlocks.length) {
94        final byte[][] newBlocks = new byte[ArrayUtil.oversize(size,
95            RamUsageEstimator.NUM_BYTES_OBJECT_REF)][];
96        System.arraycopy(freeByteBlocks, 0, newBlocks, 0, freeBlocks);
97        freeByteBlocks = newBlocks;
98      }
99      final int stop = start + numBlocks;
100     for (int i = start; i < stop; i++) {
101       freeByteBlocks[freeBlocks++] = blocks[i];
102       blocks[i] = null;
103     }
104     for (int i = stop; i < end; i++) {
105       blocks[i] = null;
106     }
107     bytesUsed.addAndGet(-(end - stop) * blockSize);
108     assert bytesUsed.get() >= 0;
109   }
110 
111   
112 
113 
114   public int numBufferedBlocks() {
115     return freeBlocks;
116   }
117 
118   
119 
120 
121   public long bytesUsed() {
122     return bytesUsed.get();
123   }
124 
125   
126 
127 
128   public int maxBufferedBlocks() {
129     return maxBufferedBlocks;
130   }
131 
132   
133 
134 
135 
136 
137 
138 
139   public int freeBlocks(int num) {
140     assert num >= 0 : "free blocks must be >= 0 but was: "+ num;
141     final int stop;
142     final int count;
143     if (num > freeBlocks) {
144       stop = 0;
145       count = freeBlocks;
146     } else {
147       stop = freeBlocks - num;
148       count = num;
149     }
150     while (freeBlocks > stop) {
151       freeByteBlocks[--freeBlocks] = null;
152     }
153     bytesUsed.addAndGet(-count*blockSize);
154     assert bytesUsed.get() >= 0;
155     return count;
156   }
157 }